package com.jy.oms.framework.asyn.task.collector;

import com.jy.oms.framework.asyn.task.constants.CacheConstants;
import com.jy.oms.framework.asyn.task.core.RedissonClientProxy;
import com.jy.oms.framework.asyn.task.executor.ITaskLifecycleListener;
import com.jy.oms.framework.asyn.task.handler.ITaskHandlerManager;
import com.jy.oms.framework.asyn.task.model.TaskHandlerWrapper;
import com.jy.oms.framework.asyn.task.model.TaskWrapper;
import com.jy.oms.framework.asyn.task.model.strategy.ExclusiveGroupExecuteStrategy;
import com.jy.oms.framework.asyn.task.model.strategy.ExclusiveSameBillExecuteStrategy;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 排他任务状态收集器
 *
 * @author liuquan
 */
@Service
public class TaskExclusiveStateCollector implements ITaskLifecycleListener {

    @Autowired
    private ITaskHandlerManager taskHandlerManager;

    /**
     * 判断任务是否能执行
     */
    public boolean canExecute(String taskCode, String billCode) {
        String cacheKey = this.genCacheKey(taskCode, billCode);
        if (cacheKey == null) {
            return true;
        }

        RedissonClient redissonClient = RedissonClientProxy.getRedissonClient();
        RBucket<Boolean> bucket = redissonClient.getBucket(cacheKey);
        boolean check = bucket.compareAndSet(null, true);
        if (check) {
            bucket.expire(15, TimeUnit.MINUTES);
        }
        return check;
    }

    private String genCacheKey(String taskCode, String billCode) {
        TaskHandlerWrapper taskHandlerWrapper = taskHandlerManager.loadTaskHandler(taskCode);
        String cacheKey = null;
        if (taskHandlerWrapper.getExecuteStrategy() instanceof ExclusiveGroupExecuteStrategy) {
            ExclusiveGroupExecuteStrategy strategy = (ExclusiveGroupExecuteStrategy) taskHandlerWrapper.getExecuteStrategy();
            String taskExclusiveGroup = strategy.getTaskExclusiveGroup();
            cacheKey = CacheConstants.genCacheKey(CacheConstants.TASK_EXCLUSIVE_EXECUTE_CHECKER, taskExclusiveGroup);
        } else if (taskHandlerWrapper.getExecuteStrategy() instanceof ExclusiveSameBillExecuteStrategy) {
            if (StringUtils.isBlank(billCode)) {
                return null;
            }

            cacheKey = CacheConstants.genCacheKey(CacheConstants.TASK_EXCLUSIVE_SAME_BILL_EXECUTE_CHECKER, billCode);
        }

        return cacheKey;
    }

    private void clear(String taskCode, String billCode) {
        String cacheKey = this.genCacheKey(taskCode, billCode);
        if (cacheKey == null) {
            return;
        }

        RedissonClient redissonClient = RedissonClientProxy.getRedissonClient();
        RBucket<Boolean> bucket = redissonClient.getBucket(cacheKey);
        if (bucket.isExists()) {
            bucket.delete();
        }
    }

    /**
     * 任务完成时清除排他标记
     *
     * @param taskWrapper 任务
     */
    @Override
    public void onFinish(TaskWrapper taskWrapper) {
        this.clear(taskWrapper.getTaskCode(), taskWrapper.getTaskDto().getBillCode());
    }

    /**
     * 链式校验时，可能已经标记了排他状态，但后续校验失败任务不可执行，因此需要清除排他标记
     *
     * @param taskWrapper 任务
     */
    @Override
    public void onFilter(TaskWrapper taskWrapper) {
        this.clear(taskWrapper.getTaskCode(), taskWrapper.getTaskDto().getBillCode());
    }

}
